package cn.datacare.orm.mapper.parameter;


import cn.datacare.orm.annotation.Param;
import cn.datacare.orm.annotation.RowSize;
import cn.datacare.orm.annotation.RowStart;
import cn.datacare.orm.exception.OrmCoreException;
import cn.datacare.orm.type.JavaType;
import cn.datacare.orm.util.kit.BeanKit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.datacare.orm.exception.OrmErrorCode.ERROR_MAPPER_PARAMETER;
import static cn.datacare.orm.exception.OrmErrorCode.ERROR_MAPPER_PARAMETER_NO_MATCH;
import static cn.datacare.orm.util.Separator.COMMA;

/**
 * 将mapper参数转化为SQLManager调用需要的Map参数，通常是mapper参数的参数名为key，但是会收到注解等配置影响
 */
public abstract class MapperParameter {
	protected String annoParam = null;
	protected Method m = null;
	protected String[] paramsName = null;
	protected boolean firstRoot = false;

	public MapperParameter(Method m) {
		this.m = m;
	}

	public MapperParameter(Method m, String annoParam) {
		this.m = m;
		this.annoParam = annoParam;
	}

	/**
	 * 根据mapper参数获取sqlmanager相应方法的参数
	 *
	 * @param array
	 * @return
	 */
	public abstract Object get(Object[] array);

	protected void addRoot(Map para, Object firstPara) {
		if (this.firstRoot) {
			para.put("_root", firstPara);
		}
	}


    /**
     * 如果配置的有annoParam
     *
     * @param array
     * @return
     * @see cn.datacare.orm.annotation.SqlStatement#params
     */
	protected Map buildByParam(Object[] array) {
		String[] names = annoParam.split(COMMA);
		if (names.length != array.length) {
			throw new OrmCoreException(ERROR_MAPPER_PARAMETER_NO_MATCH, names.toString());

		}
		Map<String, Object> map = new HashMap<>(names.length);
		for (int i = 0; i < names.length; i++) {
			map.put(names[i], array[i]);
		}
		return map;
	}

	protected String[] getParaName(int start) {
		if (JavaType.isJdk8()) {
			return getJDK8ParaName(start);
		} else {
			return getGeneralName(start);
		}
	}

	protected String[] getJDK8ParaName(int start) {

		Parameter[]  params = m.getParameters();
		Annotation[][] annotations = m.getParameterAnnotations();
		List<String> list = new ArrayList<>(params.length);
		for (int i = start; i < params.length; i++) {
			String name = getParaNameByAnnation(annotations[i]);
			if (name != null) {
				//使用注解名字优先 @Param("user1") User user -> {"user1":user}
				list.add(name);
			} else {
				//使用JDK8的parameter优先  User user1 -> {"user1":user}
				list.add(params[i].getName());
			}
		}
		return list.toArray(new String[0]);
	}


	protected String[] getGeneralName(int start) {

		Annotation[][] anns = m.getParameterAnnotations();
		List<String> list = new ArrayList<>(anns.length);
		for (int i = start; i < anns.length; i++) {
			String name = getParaNameByAnnation(anns[i]);
			if (name == null) {
				throw new OrmCoreException(ERROR_MAPPER_PARAMETER, "未命名的参数 " + start + " " + m);

			}
			list.add(name);
		}
		return list.toArray(new String[0]);
	}

	protected String getParaNameByAnnation(Annotation[] annons) {
		if (annons.length == 0) {
			return null;
		}
		Annotation p = annons[0];
		String name = null;
		if (p instanceof RowStart) {
			name = "_st";
		} else if (p instanceof RowSize) {
			name = "_sz";
		} else if (p instanceof Param) {
			name = ((Param) p).value();
		} else {
			throw new OrmCoreException(ERROR_MAPPER_PARAMETER, p, name);

		}
		return name;
	}

	protected String[] checkFirst(Method m) {
		Class[] paras = m.getParameterTypes();
		String[] parameterNames = getParaName(0);
		if (paras.length >= 1 && isRoot(paras[0])) {
			//第一个参数考虑设置为_root,
			firstRoot = true;
		}
		return parameterNames;
	}


	protected boolean isRoot(Class c) {
		if (Map.class.isAssignableFrom(c)) {
			return true;
		}
		if (c.isArray()) {
			return false;
		}
		if (c.isPrimitive()) {
			return false;
		}
		String name = BeanKit.getPackageName(c);
		if (name.startsWith("java.") || name.startsWith("javax.")) {
			return false;
		}
		return true;
	}
}
